import "./index.css";
import React from "react";
import CommonUtils from "../../utils/CommonUtils";
import PropTypes from "prop-types";

/**
 * 对话框组件
 * props: {
 *     display: {boolean} 是否显示,
 *     className: {string} 附加样式类,
 *     style: {object} 附加样式,
 *     title: {string} 标题,
 *     btns: [{title: {string} 标题, callback: {Function} 回调, closable: {boolean} 点击后是否关闭对话框, className: {string} 附加样式}] 按钮组",
 *     content: {string|ReactComponent|HTMLElement} 内容,
 *     closable: {boolean} 显示右上角关闭按钮，或点击其他区域关闭对话框,
 *     onClose: {Function} 关闭回调
 * }
 */
export default class Dialog extends React.Component{
    static propTypes = {
        display: PropTypes.bool,
        className: PropTypes.string,
        style: PropTypes.object,
        title: PropTypes.string,
        btns: PropTypes.arrayOf({
            title: PropTypes.string,
            callback: PropTypes.func,
            closable: PropTypes.bool,
            className: PropTypes.string
        }),
        content: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
        closable: PropTypes.bool,
        onClose: PropTypes.func
    };
    constructor(props){
        super(props);
        this.state = {
            //显示中(用于加载动画，先等待浏览器渲染完成，此时是隐藏状态，然后在改变style完成transition动画)
            showing: this.props.display,
            //是否显示
            display: this.props.display
        };
        this.hidden = this.hidden.bind(this);
        this.transitionEndHandler = this.transitionEndHandler.bind(this);
    }

    /**
     * 装载完成时启用动画，并绑定关闭按键事件
     */
    componentDidMount() {
        this.startAnimation();
        this.props.closable && CommonUtils.addKeyDownEventListener("Escape", this.hidden);
    }

    /**
     * 更新时，如果从隐藏到显示则启动显示动画
     */
    componentDidUpdate(prevProps, prevState, snapshot) {
        if(prevProps.display === false && this.props.display){
            this.startAnimation();
        }
    }

    /**
     * 当被卸载时移除按键监听
     */
    componentWillUnmount() {
        CommonUtils.removeKeyDownEventListener("Escape", this.hidden);
    }

    /**
     * 渲染完成时进行动画
     */
    startAnimation() {
        if(!this.props.display) return ;
        CommonUtils.waitBrowserRender(this.container);
        this.setState({showing: false});
    }

    /**
     * 处理按钮点击事件
     */
    btnClickHandler(btn, event){
        if(btn.callback instanceof Function && btn.callback(event) === false) return;
        if(btn.closable) this.hidden();
    }

    /**
     * 隐藏对话框
     */
    hidden(){
        this.setState(Object.assign({}, this.state, {hidden: true}));
    }

    /**
     * 动画结束事件
     * 如果是关闭动画，则隐藏组件
     */
    transitionEndHandler(event){
        if(!event.target.classList.contains("modal")) return;
        if(this.state.hidden){
            this.setState(Object.assign({}, this.state, {display: false}));
            if(this.props.onClose instanceof Function) this.props.onClose();
        }
    }

    render(){
        let btn,closeBtn;
        //按钮组
        if(this.props.btns.length){
            btn =
                <div className="modal-footer">
                    {
                        this.props.btns.map((btn, index) =>
                            <button type="button" key={index} className={"btn " + btn.className}
                                    onClick={this.btnClickHandler.bind(this, btn)}>{btn.title}</button>
                        )
                    }
                </div>;
        }
        //关闭按钮
        if(this.props.closable){
            closeBtn =
                <button type="button" className="close" onClick={this.hidden}>
                    <span aria-hidden="true">&times;</span>
                </button>;
        }
        return (
            <div
                ref={element=>{this.container = element}}
                /*如果浏览器正在渲染，或已经设置隐藏则隐藏，否则显示*/
                className={"modal fade" + ((this.state.showing || this.state.hidden)?"":" show")}
                role="dialog"
                style={{display: (this.state.display?"block":"none")}}
                onTransitionEnd={this.transitionEndHandler}
                onClick={event => event.target === this.container && this.hidden()}
            >
                <div className={"modal-dialog "+(this.props.className||"")} style={this.props.style}>
                    <div className="modal-content">
                        <div className="modal-header">
                            <h5 className="modal-title">{this.props.title}</h5>
                            {/*是否可关闭*/}
                            {closeBtn}
                        </div>
                        <div className="modal-body">
                            {this.props.children || this.props.content}
                        </div>
                        {btn}
                    </div>
                </div>
            </div>
        )
    }
}
